﻿#region --- License & Copyright Notice ---
/*
ConsoleFx CommandLine Processing Library

Copyright (c) 2006-2012 Jeevan James
All rights reserved.

The contents of this file are made available under the terms of the
Eclipse Public License v1.0 (the "License") which accompanies this
distribution, and is available at the following URL:
http://opensource.org/licenses/eclipse-1.0.txt

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.

By using this software in any fashion, you are agreeing to be bound by the
terms of the License.
*/
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleFx.Programs.Interactive
{
    //A general-purpose command-line argument tokenizer... accepts a string and tokenizes it.
    //Currently this is used by the interactive shell framework to manually parse the user input.
    //Regular command-line applications do not need to use this class.
    //
    //These are the rules for tokenizing:
    //1. If the token starts with a double-quote, we create a StringBuilder and add all subsequent
    //   tokens till we encounter a token that ends with a double-quote.
    //2. If the token ends with a double-quote, we return whatever is in the StringBuilder and set
    //   the StringBuilder instance to null to indicate that we're not accummulating the tokens now.
    //3. For any other token, we return it if the StringBuilder instance is null, otherwise we add
    //   the token string to the StringBuilder.
    //4. If a double-quote is within a token, then it is considered a part of the token.
    public static class Tokenizer
    {
        public static IEnumerable<string> Tokenize(string line)
        {
            return InternalTokenize(line).Where(token => !string.IsNullOrEmpty(token));
        }

        private static IEnumerable<string> InternalTokenize(string line)
        {
            if (string.IsNullOrWhiteSpace(line))
                yield break;

            string[] strings = line.Split(new[] { ' ' }, StringSplitOptions.None);

            StringBuilder sb = null;
            foreach (string str in strings)
            {
                if (sb != null)
                {
                    sb.Append(' ').Append(str);
                    if (str.EndsWith(@"""", StringComparison.OrdinalIgnoreCase))
                    {
                        yield return sb.ToString().Trim('"');
                        sb = null;
                    }
                }
                else if (str.StartsWith(@""""))
                {
                    if (str.EndsWith(@""""))
                        yield return str.Trim('"');
                    else
                        sb = new StringBuilder(str);
                }
                else
                    yield return str;
            }
            if (sb != null)
                yield return sb.ToString().Trim('"');
        }
    }
}